using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

namespace ExcelTemplateEngine.OpenXML
{
    /// <summary>
    /// 基于OpenXML的定义名称实现
    /// </summary>
    public class OpenXMLDefinedNames : IDefinedNames
    {
        private readonly WorkbookPart _workbookPart;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="workbookPart">工作簿部件</param>
        public OpenXMLDefinedNames(WorkbookPart workbookPart)
        {
            _workbookPart = workbookPart ?? throw new ArgumentNullException(nameof(workbookPart));
        }
        
        /// <summary>
        /// 添加定义名称
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        public void Add(string name, string value)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("名称不能为空", nameof(name));
            if (value == null)
                throw new ArgumentNullException(nameof(value));
                
            var definedNames = GetOrCreateDefinedNames();
            
            // 检查是否已存在，如果存在则更新
            var existing = definedNames.Elements<DefinedName>()
                .FirstOrDefault(dn => dn.Name == name);
                
            if (existing != null)
            {
                existing.Text = value;
            }
            else
            {
                var definedName = new DefinedName()
                {
                    Name = name,
                    Text = value
                };
                definedNames.Append(definedName);
            }
        }
        
        /// <summary>
        /// 获取定义名称的值
        /// </summary>
        /// <param name="name">名称</param>
        /// <returns>值</returns>
        public string? Get(string name)
        {
            if (string.IsNullOrEmpty(name))
                return null;
                
            var definedNames = _workbookPart.Workbook.GetFirstChild<DefinedNames>();
            if (definedNames == null)
                return null;
                
            var definedName = definedNames.Elements<DefinedName>()
                .FirstOrDefault(dn => dn.Name == name);
                
            return definedName?.Text;
        }
        
        /// <summary>
        /// 删除定义名称
        /// </summary>
        /// <param name="name">名称</param>
        /// <returns>是否删除成功</returns>
        public bool Remove(string name)
        {
            if (string.IsNullOrEmpty(name))
                return false;
                
            var definedNames = _workbookPart.Workbook.GetFirstChild<DefinedNames>();
            if (definedNames == null)
                return false;
                
            var definedName = definedNames.Elements<DefinedName>()
                .FirstOrDefault(dn => dn.Name == name);
                
            if (definedName != null)
            {
                definedName.Remove();
                
                // 如果没有定义名称了，删除整个DefinedNames元素
                if (!definedNames.Elements<DefinedName>().Any())
                {
                    definedNames.Remove();
                }
                
                return true;
            }
            
            return false;
        }
        
        /// <summary>
        /// 获取所有定义名称
        /// </summary>
        /// <returns>名称集合</returns>
        public IEnumerable<string> GetAllNames()
        {
            var definedNames = _workbookPart.Workbook.GetFirstChild<DefinedNames>();
            if (definedNames == null)
                return Enumerable.Empty<string>();
                
            return definedNames.Elements<DefinedName>()
                .Select(dn => dn.Name!.Value!)
                .Where(name => !string.IsNullOrEmpty(name));
        }
        
        /// <summary>
        /// 获取或创建DefinedNames元素
        /// </summary>
        /// <returns>DefinedNames元素</returns>
        private DefinedNames GetOrCreateDefinedNames()
        {
            var definedNames = _workbookPart.Workbook.GetFirstChild<DefinedNames>();
            if (definedNames == null)
            {
                definedNames = new DefinedNames();
                _workbookPart.Workbook.AppendChild(definedNames);
            }
            return definedNames;
        }
    }
}